package com.xiyuan.smartutils;

import com.xiyuan.smartutils.constants.SignConstants;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 列表相关工具类
 * 1.继承Collectionx类，实现基于集合的基础工具功能
 * 2.继承Listx类，实现基于的列表基础工具功能
 * 3.创建Lists类，实现扩展的列表功能
 *
 * @version v1.0.0 @author lgz 2017-8-27 新建与整理
 */

@SuppressWarnings({"unchecked", "DanglingJavadoc", "FinalStaticMethod"})
public final class Lists implements SignConstants {
    private Lists() {}
    
    public static int size(Collection<?> list) {
        return (list == null) ? 0 : list.size();
    }
    
    public static boolean isEmpty(Collection<?> list) {
        return list == null || list.isEmpty();
    }
    
    public static boolean contains(Collection<?> collection, Object o) {
        return collection != null && collection.contains(o);
    }
    
    public static <E> Iterator<E> iterator(Collection<E> list) {
        return list.iterator();
    }
    
    public static <T> T[] toArray(Collection<T> list) {
        return (T[]) list.toArray();
    }
    
    public static <T> T[] toArray(Collection<T> list, T[] a) {
        return list.toArray(a);
    }
    
    // Modification Operations 修改操作
    public static <E> boolean add(Collection<E> list, E e) {
        return list != null && list.add(e);
    }
    
    public static boolean remove(Collection<?> list, Object o) {
        return list != null && list.remove(o);
    }
    
    // Bulk Modification Operations 批量修改操作
    
    public static boolean containsAll(Collection<?> list, Collection<?> c) {
        return list != null && list.containsAll(c);
    }
    
    public static <E> boolean addAll(Collection<E> list, Collection<? extends E> c) {
        return list != null && list.addAll(c);
    }
    
    public static <E> boolean addAll(List<E> list, int index, Collection<? extends E> c) {
        return list != null && list.addAll(index, c);
    }
    
    public static boolean removeAll(List<?> list, Collection<?> c) {
        return list != null && list.removeAll(c);
    }
    
    public static boolean retainAll(Collection<?> list, Collection<?> c) {
        return list != null && list.retainAll(c);
    }
    
    public static void clear(Collection<?> list) {
        if (list != null) {list.clear();}
    }
    
    // Comparison and hashing  
    
    public static boolean equals(Collection<?> list, Object o) {
        return list.equals(o);
    }
    
    public static int hashCode(Collection<?> list) {
        return list.hashCode();
    }
    
    // Positional Access Operations 
    public static <E> E get(List<E> list, int index) {
        return list.get(index);
    }
    
    public static <E> E set(List<E> list, int index, E element) {
        return list.set(index, element);
    }
    
    public static <E> void add(List<E> list, int index, E element) {
        list.add(index, element);
    }
    
    public static <E> E remove(List<E> list, int index) {
        return list.remove(index);
    }
    
    public static int indexOf(List<?> list, Object o) {
        return list.indexOf(o);
    }
    
    public static int lastIndexOf(List<?> list, Object o) {
        return list.lastIndexOf(o);
    }
    
    public static <E> ListIterator<E> listIterator(List<E> list) {
        return list.listIterator();
    }
    
    public static <E> ListIterator<E> listIterator(List<E> list, int index) {
        return list.listIterator(index);
    }
    
    public static <E> List<E> subList(List<E> list, int fromIndex, int toIndex) {
        return list.subList(fromIndex, toIndex);
    }
    
    /***********************************************************************************/
    //以下为拷贝出一个新的列表
    /***********************************************************************************/
    
    /**
     * 拷贝到新列表中
     *
     * @param list 列表
     * @return 新列表
     */
    public static final <E> List<E> copy(List<E> list) {
        return new ArrayList<E>(list);
    }
    
    public static final <E> List<E> copy(List<E> list, boolean sync) {
        if (sync) {
            synchronized (list) {
                List<E> newList = new ArrayList<E>(list.size());
                newList.addAll(list);
                return newList;
            }
        }
        else {
            List<E> newList = new ArrayList<E>(list.size());
            newList.addAll(list);
            return newList;
        }
    }
    
    /**
     * 拷贝前n个到新列表中
     *
     * @param list 列表
     * @param n    数目
     * @return 新列表
     */
    public static final <E> List<E> copy(List<E> list, int n) {
        List<E> newList = new ArrayList<E>();
        for (int i = 0; i < n; i++) {
            newList.add(list.get(i));
        }
        
        return newList;
    }
    
    /**
     * 拷贝新的列表，并重新设置一个元素
     *
     * @param index   索引号
     * @param element 元素
     * @return 新列表
     */
    public static final <E> List<E> copySet(List<E> list, int index, E element) {
        List<E> newList = new ArrayList<>(list);
        newList.set(index, element);
        return newList;
    }
    
    /**
     * 新拷贝一个列表，再增加一个元素
     *
     * @param list    列表
     * @param element 元素
     * @return 新列表
     */
    public static final <E> List<E> copyAdd(List<E> list, E element) {
        List<E> newList = new ArrayList<>(list);
        newList.add(element);
        return newList;
    }
    
    /**
     * 新拷贝一个列表，再增加一个元素到指定位置
     *
     * @param list    列表
     * @param index   索引号
     * @param element 元素
     * @return 新列表
     */
    public static final <E> List<E> copyAdd(List<E> list, int index, E element) {
        List<E> newList = new ArrayList<>(list);
        newList.add(index, element);
        return newList;
    }
    
    /**
     * 获取删除指定索引的新的列表
     *
     * @param list  列表
     * @param index 索引号
     * @return 新列表
     */
    public static final <E> List<E> copyRemove(List<E> list, int index) {
        List<E> newList = new ArrayList<>(list);
        newList.remove(index);
        return newList;
    }
    
    /***********************************************************************************/
    //以下为数组转为列表相关功能
    /***********************************************************************************/
    
    /**
     * 清除ArrayList的size之外的无效引用
     *
     * @param list 列表
     * @return 清除之后的列表
     */
    public static <T> ArrayList<T> trim(ArrayList<T> list) {
        list.trimToSize();
        return list;
    }
    
    /**
     * 清除ArrayList的size之外的无效引用
     *
     * @param list 列表
     * @return 清除之后的列表
     */
    public static <T> List<T> trim(List<T> list) {
        if (!(list instanceof ArrayList)) {return list;}
        
        ((ArrayList<T>) list).trimToSize();
        return list;
    }
    
    /**
     * 排序并返回对象
     *
     * @param list       列表
     * @param comparator 比较器
     * @return 排序之后列表
     */
    public static <T> List<T> sort(List<T> list, Comparator<T> comparator) {
        if (!list.isEmpty()) {list.sort(comparator);}
        return list;
    }
    
    /**
     * 排序并返回对象
     *
     * @param list       列表
     * @param comparator 比较器
     * @return 排序之后列表
     */
    public static <T> ArrayList<T> sort(ArrayList<T> list, Comparator<T> comparator) {
        if (!list.isEmpty()) {list.sort(comparator);}
        return list;
    }
    
    /**
     * 排序清理，并返回对象
     *
     * @param list       列表
     * @param comparator 比较器
     * @return 排序之后列表
     */
    public static <T> ArrayList<T> sortAndTrim(ArrayList<T> list, Comparator<T> comparator) {
        if (!list.isEmpty()) {list.sort(comparator);}
        list.trimToSize();
        return list;
    }
    
    /**
     * 数组转列表
     *
     * @param arr 数组对象
     * @return 结果为列表
     */
    public static <T> List<T> toList(T[] arr) {
        if (arr == null) {return new ArrayList<T>();}
        
        List<T> list = new ArrayList<T>(arr.length);
        Collections.addAll(list, arr);
        
        return list;
    }
    
    /**
     * int[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Integer> toList(int[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * long[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Long> toList(long[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * byte[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Byte> toList(byte[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * short[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Short> toList(short[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * char[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Character> toList(char[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * boolean[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Boolean> toList(boolean[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * float[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Float> toList(float[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /**
     * double[]转列表
     *
     * @param arr 数组
     * @return 列表
     */
    public static List<Double> toList(double[] arr) {
        return toList(Arrays.convert(arr));
    }
    
    /***********************************************************************************/
    //以下为列表和字符串转换相关功能
    /***********************************************************************************/
    
    /**
     * 把字符串按逗号分隔转换成字符串数组，注意每个字符串都将trim()操作去除前后空字符串(空格,\r,\n,\t,\b等)
     *
     * @param strs 字符串
     * @return String[] 转换后的去除前后空格的字符串数组(空格,\r,\n,\t,\b等)
     */
    public static List<String> toStringList(String strs) {
        return toStringList(strs, ",");
    }
    
    /**
     * 把字符串按split分隔转换成字符串数组，注意每个字符串都将trim()操作去除前后空字符串(空格,\r,\n,\t,\b等)
     *
     * @param strs      字符串
     * @param separator 分隔符
     * @return String[] 转换后的去除前后空格的字符串数组(空格,\r,\n,\t,\b等)
     */
    public static List<String> toStringList(String strs, String separator) {
        if (Validates.isEmpty(strs)) {return new ArrayList<String>();}
        
        ArrayList<String> strList = new ArrayList<String>();
        String[] array = strs.split(separator);
        for (int i = 0; i < array.length; i++) {strList.add(array[i].trim());}
        
        strList.trimToSize();
        return strList;
    }
    
    /**
     * 把字符串按逗号“,”分隔转换成整型列表
     *
     * @param strs 字符串
     * @return List<Integer> 转换后的整数列表
     */
    public static List<Integer> toIntList(String strs) {
        return toIntList(strs, ",");
    }
    
    /**
     * 把字符串按split分隔转换成整型列表
     *
     * @param strs      字符串
     * @param separator 分隔符
     * @return List<Integer> 转换后的整数列表
     */
    public static List<Integer> toIntList(String strs, String separator) {
        List<String> strList = toStringList(strs, separator);
        return toIntList(strList);
    }
    
    /**
     * 把字符串列表传换成整型列表
     *
     * @param strList 字符串列表
     * @return List<Integer> 转换后的整型列表
     */
    public static List<Integer> toIntList(List<String> strList) {
        List<Integer> intList = new ArrayList<Integer>(strList.size());
        for (String str : strList) {intList.add(Integer.parseInt(str.trim()));}
        return intList;
    }
    
    /**
     * 把字符串按逗号“,”分隔转换成长整型列表
     *
     * @param strs 字符串
     * @return List<Long> 转换后的整数列表
     */
    public static List<Long> toLongList(String strs) {
        return toLongList(strs, ",");
    }
    
    /**
     * 把字符串按split分隔转换成长整型列表
     *
     * @param strs      字符串
     * @param separator 分隔符
     * @return List<Long> 转换后的整数列表
     */
    public static List<Long> toLongList(String strs, String separator) {
        List<String> strList = toStringList(strs, separator);
        return toLongList(strList);
    }
    
    /**
     * 把字符串列表转换成长整型列表
     *
     * @param strList 字符串列表
     * @return List<Long> 转换后的长整型列表
     */
    public static List<Long> toLongList(List<String> strList) {
        List<Long> longList = new ArrayList<Long>();
        for (String str : strList) {longList.add(Long.parseLong(str.trim()));}
        return longList;
    }
    
    /**
     * 列表转换成逗号“,”分隔的字符串
     *
     * @param list 对象列表，如List<String>,List<Integer>,List<Long>等
     * @return 分隔符分隔的字符串, 如 abc,def,pdf
     */
    public static String toString(List<?> list) {
        return toString(list, ",");
    }
    
    /**
     * 列表转换成分隔符分隔的字符串
     *
     * @param list      对象列表，如List<String>,List<Integer>,List<Long>等
     * @param separator 分隔符
     * @return 分隔符分隔的字符串, 如 abc,def,pdf
     */
    public static String toString(List<?> list, String separator) {
        if (list == null || list.size() == 0) {return _EMPTY_;}
        
        StringBuilder strb = new StringBuilder().append(list.get(0));
        for (int i = 1; i < list.size(); i++) {
            strb.append(separator).append(list.get(i));
        }
        
        return strb.toString();
    }
    
    /**
     * 列表初始化填充到指定索引位置
     *
     * @param list    列表
     * @param toIndex 索引位置
     * @param elem    初始对象
     */
    public static <T> void fill(List<T> list, int toIndex, T elem) {
        while (list.size() < toIndex) {list.add(elem);}
    }
    
    /*********************************************/
    //以下列表相关工具功能
    /*********************************************/
    
    /**
     * 列表位置反转倒序
     *
     * @param oldList 顺序
     * @return newList 倒序
     */
    public static <T> ArrayList<T> reverse(ArrayList<T> oldList) {
        ArrayList<T> newList = new ArrayList<T>(oldList.size());
        for (int i = oldList.size() - 1; i >= 0; i--) {
            newList.add(oldList.get(i));
        }
        
        newList.trimToSize();
        return newList;
    }
    
    /**
     * 检查列表中对象的属性中是否匹配指定的值
     *
     * @param list       集合
     * @param field      对象中的属性名
     * @param equalValue 指定的值
     */
    public static boolean contains(Collection<?> list, String field, Object equalValue) {
        if (list == null || list.isEmpty()) {return false;}
        
        if (field == null) {return list.contains(equalValue);}
        
        //通过反射机制取属性
        for (Object obj : list) {
            if (obj == null) {continue;}
            
            Field f = Classes.getFieldDeep(obj.getClass(), field);
            if (f == null) {continue;}
            
            Object v = Classes.getFieldValue(obj, f);
            if (Validates.isEqual(equalValue, v)) {return true;}
        }
        
        return false;
    }
    
    /**
     * 检查列表中对象的属性中是否有匹配指定的值，有则返回该对象
     *
     * @param list       集合
     * @param field      对象中的属性名
     * @param equalValue 指定的值
     * @return 集合中第一个匹配上的对象，如果没有一个匹配则返回null
     */
    public static <T> T get(Collection<T> list, String field, Object equalValue) {
        if (list == null || list.isEmpty() || equalValue == null) {return null;}
        
        for (T obj : list) {
            if (obj == null) {continue;}
            
            if (field == null) {
                if (Validates.isEqual(equalValue, obj)) {return obj;}
            }
            else {
                Field f = Classes.getFieldDeep(obj.getClass(), field);
                if (f == null) {continue;}
                
                Object v = Classes.getFieldValue(obj, f);
                if (Validates.isEqual(equalValue, v)) {return obj;}
            }
        }
        
        return null;
    }
    
    /**
     * 字符串s是否是含有通配符*的pattern能匹配上，如/abc/cde.gif匹配上/a*c/*de.*
     *
     * @param s       字符串
     * @param pattern 含通配符*的字符串，注意该方法中*至少占一个字符
     * @return 得到匹配的字符串列表
     */
    public static List<String> getMatchList(String s, String pattern) {
        if (s == null || pattern == null) {return null;}
        
        int ind = pattern.indexOf("*");
        if (ind == -1) {//如果匹配字符串不含通配符，则比较两字符串是否相等
            return s.equals(pattern) ? new ArrayList<String>() : null;
        }
        
        ArrayList<String> matchList = new ArrayList<>();
        while (true) {
            if (s.length() <= ind) {//长度不够没匹配上
                return null;
            }
            
            if (ind > 0) {//取出*号前面的内容
                String match = pattern.substring(0, ind);
                if (!s.startsWith(match)) {//没有匹配上*号前面的内容
                    return null;
                }
                
                //抹除*号前面的内容，使得*号在第一个位置上
                pattern = pattern.substring(ind);
                s = s.substring(ind);
            }
            
            //去除*号
            pattern = pattern.substring(1);
            if (Validates.isEmpty(pattern)) {//*号是最后一个字符表示成功
                matchList.add(s);
                matchList.trimToSize();
                return matchList;
            }
            
            //由于*号必须占一个字符，所以s也需要先去除一个字符再比较
            String temp = s.substring(0, 1);
            s = s.substring(1);
            
            //下一个*号
            ind = pattern.indexOf("*");
            if (ind == -1) {//后面没有*号，比较是否后缀匹配成功
                if (!s.endsWith(pattern)) {//没匹配成功
                    return null;
                }
                
                //成功取通匹值
                String match = temp + StrUtils.trimRight(s, pattern);
                matchList.add(match);
                matchList.trimToSize();
                return matchList;
            }
            
            String match = pattern.substring(0, ind);
            int aInd = s.indexOf(match);
            if (aInd == -1) {return null;}
            
            if (aInd == 0) {//只匹配到一个字符
                matchList.add(temp);
            }
            else {//查到*号对应的内容，放置到通匹符表中，再去除进入下一个*号循环
                matchList.add(temp + s.substring(0, aInd));
                s = s.substring(aInd);
            }
        }
    }
}
